package com.robot.member.controller;

import com.alibaba.fastjson.JSON;
import com.robot.member.client.OrdersClient;
import com.robot.member.client.SmsClient;
import com.robot.member.pojo.Consumption;
import com.robot.member.pojo.Member;
import com.robot.member.pojo.vo.Authorization;
import com.robot.member.pojo.vo.AuthorizationAccessToken;
import com.robot.member.pojo.vo.WeChatInfo;
import com.robot.member.service.ConsumptionService;
import com.robot.member.service.MemberService;
import com.robot.member.service.WeChatService;
//import util.QrCodeUtil;
import entity.PageResult;
import entity.Result;
import entity.Sms;
import entity.StatusCode;
import io.jsonwebtoken.Claims;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.Page;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;
import util.CheckUtil;
import util.JwtUtil;
//import util.QrCodeUtil;
import util.qr.entity.HeadImage;
import util.qr.entity.NickName;
import util.qr.entity.QrCode;
import util.qr.handler.PosterUtil;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;


/**
 * member控制器层
 *
 * @author wuyunbin
 */
@RestController
@CrossOrigin
@RequestMapping("/member")
public class MemberController {
    @Autowired
    private MemberService memberService;

    @Autowired
    private ConsumptionService consumptionService;

    @Autowired
    private WeChatService weChatService;

    @Autowired
    private OrdersClient ordersClient;

    @Autowired
    private HttpServletRequest request;

    @Autowired
    private BCryptPasswordEncoder encoder;

    @Autowired
    private CheckUtil checkUtil;

    @Autowired
    private JwtUtil jwtUtil;

    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    private final String enable = "1";

    /**
     * 填写手机号送的码豆数量
     */
    @Value("${sys.member.afterWriterPhoneSendBeans}")
    private int afterWriterPhoneSendBeans;
    /**
     * 分享送码豆数量
     */
    @Value("${sys.member.afterShareSendBeans}")
    private int afterShareSendBeans;

    @Autowired
    private SmsClient smsClient;


    /**
     * 检验token
     *
     * @return
     */
    @RequestMapping(value = "checkToken", method = RequestMethod.GET)
    public Result checkToken() {
        Member member=memberService.findByClaims(request);
        if (member == null) {
            logger.info("member is not in Db");
            return new Result(StatusCode.ERROR_USER_DOES_NOTE_EXIST);
        }
        if (!enable.equals(member.getStatus())) {
            logger.info("member status invalid");
            return new Result(StatusCode.ERROR_USER_INVALID);
        }
        return new Result(StatusCode.SUCCESS_VERIFY);
    }

    /**
     * 通过token获取会员
     *
     * @return 会员信息
     */
    @RequestMapping(value = "/findByToken", method = RequestMethod.GET)
    public Result findByToken() {
        Claims claims = (Claims) request.getAttribute("robot_member");
        if (claims == null) {
            return new Result(StatusCode.ERROR_TOKEN_EXPIRED);
        }
        logger.info("claims.getId()=" + claims.getId());

        Member memberInDb = memberService.findById(claims.getId());
        logger.info("findByToken's memberInDb=" + memberInDb);
        if (memberInDb == null) {
            return new Result(StatusCode.ERROR_USER_DOES_NOTE_EXIST);
        }
        if (!enable.equals(memberInDb.getStatus())) {
            return new Result(StatusCode.ERROR_RECORD_DOES_NOTE_EXIST);
        }
        return new Result(StatusCode.SUCCESS_QUERY, memberInDb);
    }

    /**
     * 修改密码
     *
     * @param member    会员对象
     * @param checkCode 验证码
     * @return Result
     */
    @RequestMapping(value = "updatePassword/{checkCode}", method = RequestMethod.PUT)
    @Transactional(rollbackFor = Exception.class)
    public Result updatePassword(@PathVariable String checkCode, @RequestBody Member member) {
        Claims claims = (Claims) request.getAttribute("robot_member");
        if (claims == null) {
            return new Result(StatusCode.ERROR_TOKEN_EXPIRED);
        }
        logger.info("claims.getId()=" + claims.getId());
        //前端调用findByToken接口检查过了,所以这里不再对会员是否存在和状态进行判断
        Member memberInDb = memberService.findById(claims.getId());

        String phone = member.getPhone();
        checkCode = checkCode.trim();
        if ("".equals(checkCode)) {
            return new Result(StatusCode.ERROR_VERIFICATION_CODE);
        }
        //验证码是不是过期
        Sms sms = new Sms("member", phone, "updatePassword");

        if (!smsClient.isCheckCodeExpire(sms)) {
            return new Result(StatusCode.ERROR_VERIFICATION_CODE_EXPIRED);
        }
        //验证码是否正确
        if (!smsClient.isCorrectCheckCode(sms, checkCode)) {
            return new Result(StatusCode.ERROR_VERIFICATION_CODE);
        }

        if (member.getPassword() != null && !"".equals(member.getPassword())) {
            memberInDb.setPassword(encoder.encode(member.getPassword()));
        } else {
            return new Result(StatusCode.ERROR_PASSWORD_REQUIRED);
        }
        memberInDb.setUpdatedAt(LocalDateTime.now());
        memberService.update(memberInDb);
        smsClient.deleteCheckCode(sms);
        return new Result(StatusCode.SUCCESS_UPDATED);
    }

    /**
     * 找回密码
     *
     * @param member    会员对象
     * @param checkCode 验证码
     * @return result
     */
    @RequestMapping(value = "findPassword/{checkCode}", method = RequestMethod.PUT)
    @Transactional(rollbackFor = Exception.class)
    public Result findPassword(@PathVariable String checkCode, @RequestBody Member member) {
        String phone = member.getPhone();
        if (member.getPhone() == null || "".equals(member.getPhone())) {
            return new Result(StatusCode.ERROR_PHONE_REQUIRED);
        } else if (!checkUtil.checkPhone(member.getPhone())) {
            return new Result(StatusCode.ERROR_INVALID_PHONE);
        }
        Member memberInDb = memberService.findByPhone(phone);
        if (memberInDb == null) {
            return new Result(StatusCode.ERROR_USER_DOES_NOTE_EXIST);
        }
        if (!enable.equals(memberInDb.getStatus())) {
            return new Result(StatusCode.ERROR_RECORD_DOES_NOTE_EXIST);
        }

        checkCode = checkCode.trim();
        if ("".equals(checkCode)) {
            return new Result(StatusCode.ERROR_VERIFICATION_CODE);
        }
        //验证码是不是过期
        Sms sms = new Sms("member", phone, "findPassword");

        if (!smsClient.isCheckCodeExpire(sms)) {
            return new Result(StatusCode.ERROR_VERIFICATION_CODE_EXPIRED);
        }
        //验证码是否正确
        if (!smsClient.isCorrectCheckCode(sms, checkCode)) {
            return new Result(StatusCode.ERROR_VERIFICATION_CODE);
        }

        if (member.getPassword() != null && !"".equals(member.getPassword())) {
            memberInDb.setPassword(encoder.encode(member.getPassword()));
        } else {
            return new Result(StatusCode.ERROR_PASSWORD_REQUIRED);
        }
        memberService.update(memberInDb);
        smsClient.deleteCheckCode(sms);
        return new Result(StatusCode.SUCCESS_UPDATED);
    }


    /**
     * 修改手机号
     *
     * @param member
     * @param checkCode
     * @return
     */
    @PutMapping("updatePhone/{checkCode}")
    @Transactional(rollbackFor = Exception.class)
    public Result updatePhone(@PathVariable String checkCode, @RequestBody Member member) {
        Claims claims = (Claims) request.getAttribute("robot_member");
        if (claims == null) {
            return new Result(StatusCode.ERROR_TOKEN_EXPIRED);
        }
        logger.info("claims.getId()=" + claims.getId());
        //前端调用findByToken接口检查过了,所以这里不再对会员是否存在和状态进行判断

        String phone = member.getPhone();
        if (!checkUtil.checkPhone(phone)) {
            return new Result(StatusCode.ERROR_INVALID_PHONE);
        }
        if (phone.equals(claims.getSubject())) {
            return new Result(StatusCode.ERROR);
        }
        Member memberInDb = memberService.findById(claims.getId());
        if (memberInDb == null) {
            return new Result(StatusCode.ERROR_USER_DOES_NOTE_EXIST);
        }
        if (!enable.equals(memberInDb.getStatus())) {
            return new Result(StatusCode.ERROR_USER_INVALID);
        }
        if (memberService.findByPhone(phone) != null) {
            return new Result(StatusCode.ERROR_PHONE_ALREADY_EXISTS);
        }

        checkCode = checkCode.trim();
        if ("".equals(checkCode)) {
            return new Result(StatusCode.ERROR_VERIFICATION_CODE);
        }
        //验证码是不是过期
        Sms sms = new Sms("member", phone, "updatePhone");
        if (!smsClient.isCheckCodeExpire(sms)) {
            return new Result(StatusCode.ERROR_VERIFICATION_CODE_EXPIRED);
        }
        //验证码是否正确
        if (!smsClient.isCorrectCheckCode(sms, checkCode)) {
            return new Result(StatusCode.ERROR_VERIFICATION_CODE);
        }

        memberInDb.setPhone(member.getPhone());
        memberInDb.setUpdatedAt(LocalDateTime.now());
        memberService.update(memberInDb);
        smsClient.deleteCheckCode(sms);
        //修改了手机号之后返回一个新的token
        Map<String, Object> map = new HashMap<>(4);
        String role = "member";
        String token = jwtUtil.createJwt(memberInDb.getId(), memberInDb.getOpenId(), role);
        map.put("role", role);
        map.put("token", token);
        map.put("memberId", memberInDb.getId());
        map.put("openId", memberInDb.getOpenId());
        return new Result(StatusCode.SUCCESS_UPDATED, map);
    }

    /**
     * 修改
     *
     * @param member
     */
    @RequestMapping(value = "update", method = RequestMethod.PUT)
    @Transactional(rollbackFor = Exception.class)
    public Result update(@RequestBody Member member) {
        Claims claims = (Claims) request.getAttribute("robot_member");
        if (claims == null) {
            return new Result(StatusCode.ERROR_TOKEN_EXPIRED);
        }
        logger.info("claims.getId()=" + claims.getId());
        //前端调用findByToken接口检查过了,所以这里不再对会员是否存在和状态进行判断

        logger.info("member=" + member);
        Member memberInDb = memberService.findById(claims.getId());
        String responseMsg = "修改成功";
        if (member.getNickname() != null && !"".equals(member.getNickname())) {
            memberInDb.setNickname(member.getNickname());
            responseMsg = "昵称更新成功";
        }
        if (member.getEmail() != null && !"".equals(member.getEmail())) {
            if (checkUtil.checkEmail(member.getEmail())) {
                return new Result(StatusCode.ERROR, "邮箱格式不正确");
            }
            memberInDb.setEmail(member.getEmail());
            responseMsg = "邮箱更新成功";
        }
        if (member.getAvatar() != null && !"".equals(member.getAvatar())) {
            if (!checkUtil.checkImage(member.getAvatar())) {
                return new Result(StatusCode.ERROR, "头像上传失败,请重新上传");
            }
            responseMsg = "头像更新成功";
        }
        if (member.getSex() != null && !"".equals(member.getSex())) {
            /*
              性别 0-女 1-男 2-未知
             */
            String sexMale = "0";
            String sexFemale = "1";
            String sexUnknown = "2";
            if (member.getSex().equals(sexMale) || member.getSex().equals(sexFemale) || member.getSex().equals(sexUnknown)) {
                memberInDb.setSex(member.getSex());
                responseMsg = "性别更新成功";
            } else {
                return new Result(StatusCode.ERROR, "请选择正确的性别(男/女/保密)");
            }
        }
        if (member.getBirthday() != null && memberInDb.getBirthday() == null) {
            memberInDb.setBirthday(member.getBirthday());
            responseMsg = "生日更新成功";
        }
        memberInDb.setUpdatedAt(LocalDateTime.now());
        logger.info("memberInDb=" + memberInDb);
        memberService.update(memberInDb);
        return new Result(StatusCode.SUCCESS_UPDATED);
    }

    /**
     * 填写手机号送码豆
     *
     * @param member
     * @return
     */
    @RequestMapping(value = "giveBeansAfterWritePhone", method = RequestMethod.PUT)
    public Result giveBeansAfterWritePhone(@RequestBody Member member) {
        Claims claims = (Claims) request.getAttribute("robot_member");
        if (claims == null) {
            return new Result(StatusCode.ERROR_TOKEN_EXPIRED);
        }
        logger.info("claims.getId()=" + claims.getId());
        //前端调用findByToken接口检查过了,所以这里不再对会员是否存在和状态进行判断

        //判断手机号是否可用
        String phone = member.getPhone().trim();
        if (!checkUtil.checkPhone(phone)) {
            return new Result(StatusCode.ERROR_INVALID_PHONE);
        }
        if (memberService.findByPhone(phone) != null) {
            return new Result(StatusCode.ERROR_PHONE_ALREADY_EXISTS);
        }

        Member memberInDb = memberService.findById(claims.getId());
        logger.info("memberInDb=" + memberInDb);
        //前端调用findByToken接口检查过了,所以这里不再对会员是否存在和状态进行判断
        if (!"".equals(memberInDb.getPhone())) {
            return new Result(StatusCode.ERROR, "已经填过手机号了");
        }

        memberInDb.setPhone(phone);
        memberInDb.setBeans(memberInDb.getBeans() + afterWriterPhoneSendBeans);
        memberInDb.setTotalBeans(memberInDb.getTotalBeans() + afterWriterPhoneSendBeans);
        memberInDb.setUpdatedAt(LocalDateTime.now());

        //增加码豆消费记录
        Consumption consumption = new Consumption();
        consumption.setMemberId(claims.getId());
        consumption.setMemberName(memberInDb.getNickname());
        consumption.setBeans(afterWriterPhoneSendBeans);
        consumption.setType("0");
        consumption.setRemark("填写手机号送码豆");
        consumptionService.add(consumption);
        memberService.update(memberInDb);

        return new Result(StatusCode.SUCCESS);
    }

    /**
     * 我的码豆
     *
     * @return
     */
    @RequestMapping(value = "myBeans", method = RequestMethod.GET)
    public Result findBeans() {
        Claims claims = (Claims) request.getAttribute("robot_member");
        if (claims == null) {
            return new Result(StatusCode.ERROR_TOKEN_EXPIRED);
        }
        logger.info("claims.getId()=" + claims.getId());
        //前端调用findByToken接口检查过了,所以这里不再对会员是否存在和状态进行判断

        Member memberInDb = memberService.findById(claims.getId());
        HashMap<String, Object> map = new HashMap<>(2);
        map.put("beans", memberInDb.getBeans());
        map.put("goldenBeans", memberInDb.getGoldenBeans());
        map.put("totalBeans", memberInDb.getTotalBeans());

        return new Result(StatusCode.SUCCESS_QUERY, map);
    }

    /**
     * 累计节省
     *
     * @return
     */
    @RequestMapping(value = "getMemberDiscountAmount", method = RequestMethod.GET)
    public Result getMemberDiscountAmount() {
        Claims claims = (Claims) request.getAttribute("robot_member");
        if (claims == null) {
            return new Result(StatusCode.ERROR_TOKEN_EXPIRED);
        }
        logger.info("claims.getId()=" + claims.getId());
        //前端调用findByToken接口检查过了,所以这里不再对会员是否存在和状态进行判断
        return null;
//        return new Result(StatusCode.SUCCESS_QUERY, JSON.parse(ordersClient.thirdFindSubOrderDiscountAmountByMemberId(claims.getId())));
    }


    /**
     * 我的团队
     *
     * @param page
     * @param size
     * @return
     */
    @RequestMapping(value = "myTeam/{page}/{size}", method = RequestMethod.GET)
    public Result myTeam(@PathVariable int page, @PathVariable int size) {
        Claims claims = (Claims) request.getAttribute("robot_member");
        if (claims == null) {
            return new Result(StatusCode.ERROR_TOKEN_EXPIRED);
        }
        logger.info("claims.getId()=" + claims.getId());
        //前端调用findByToken接口检查过了,所以这里不再对会员是否存在和状态进行判断

        Page<Member> pageData = memberService.findAllByRecommendIdOrderByCreatedAtDesc(claims.getId(), page, size);
        return new Result(StatusCode.SUCCESS_QUERY, new PageResult<Member>(pageData.getTotalElements(), pageData.getContent()));
    }

    /**
     * 生成不带有logo二维码
     *
     * @param response
     * @param url
     * @throws Exception
     */

    @RequestMapping(value = "/getCommonQRCode", method = RequestMethod.GET)
    public void getCommonQrCode(HttpServletResponse response, String url) throws Exception {
        ServletOutputStream stream = null;
        try {
            stream = response.getOutputStream();
            //使用工具类生成二维码
//            QrCodeUtil.encode(url, stream);
        } finally {
            if (stream != null) {
                stream.flush();
                stream.close();
            }
        }
    }

    /**
     * 生成带有logo二维码
     *
     * @param response
     * @param url
     * @throws Exception
     */
    @GetMapping(value = "/getQRCodeWithLogo")
    public void getQrCodeWithLogo(HttpServletResponse response, String url) throws Exception {
        ServletOutputStream stream = null;
        try {
            stream = response.getOutputStream();
            // logo 地址
            String logoPath = "robot_member/upload/1.jpeg";
            // String logoPath = "springboot-demo-list/qr-code/src/main/resources/templates/advator.jpg";
            //使用工具类生成二维码
//            QrCodeUtil.encode(url, logoPath, stream, true);
        } finally {
            if (stream != null) {
                stream.flush();
                stream.close();
            }
        }
    }

    /**
     * 分享登录
     * A分享了一张二维码
     * B扫描该二维码,判断B的信息(手机号不存在才新增并登录B同时送A码豆)
     * B要填哪些信息(我清楚需求,暂时只要手机号即可)
     *
     * @return
     */

    @RequestMapping(value = "/shared/{recommendId}/{code}", method = RequestMethod.GET)
    public Result loginByWeChat(@PathVariable String recommendId, @PathVariable String code) {
        logger.info("code=" + code);
        //通过code获取授权accessToken和openId
        AuthorizationAccessToken accessToken = weChatService.getAuthorizationAccessToken(code);
        logger.info("accessToken=" + accessToken.toString());
        //通过accessToken和openId 获取微信用户信息
        WeChatInfo weChatInfo = weChatService.getUserInfoByAuthorizationAccessTokenAndOpenId(accessToken.getAccessToken(), accessToken.getOpenId());
        //检查这个微信号是否已经是会员，如果是直接登录，如果不是则注册之后再登录
        Member member = memberService.findByOpenId(weChatInfo.getOpenId());
        if (member == null) {
            //A的信息
            Member memberInDb = memberService.findById(recommendId + "");
            logger.info("memberInDb=" + memberInDb);
            if (memberInDb == null) {
                logger.info("member is not in Db");
                //当会员A不存在时是否给B登录,这里是报错不登录
                return new Result(StatusCode.ERROR_USER_DOES_NOTE_EXIST);
            }
            //增加A码豆数量
            memberInDb.setBeans(memberInDb.getBeans() + afterShareSendBeans);
            memberInDb.setTotalBeans(memberInDb.getTotalBeans() + afterShareSendBeans);
            memberService.update(memberInDb);

            //注册B
            member = memberService.addByWeChat(weChatInfo, recommendId);
            logger.info("开始组装返回信息");
            //登录B
            String role = "member";
            String memberId = member.getId();
            String token = jwtUtil.createJwt(memberId, member.getOpenId(), role);
            Authorization authorization = new Authorization(memberId, weChatInfo.getOpenId(), role, token);
            logger.info(authorization.toString());
            return new Result(StatusCode.SUCCESS, authorization);
        } else {
            //已经存在用户，返回报错并直接登录这个已存在的用户
            String role = "member";
            String memberId = member.getId();
            String token = jwtUtil.createJwt(memberId, member.getOpenId(), role);
            Authorization authorization = new Authorization(memberId, weChatInfo.getOpenId(), role, token);
            return new Result(StatusCode.ERROR_USER_ALREADY_EXISTS,authorization);
        }

    }


    /**
     * 实名认证
     *
     * @param map
     * @return
     */
    @RequestMapping(value = "/real_name_verified", method = RequestMethod.POST)
    public Result realNameVerified(@RequestBody HashMap<String, String> map) {
        Claims claims = (Claims) request.getAttribute("robot_member");
        if (claims == null) {
            return new Result(StatusCode.ERROR_TOKEN_EXPIRED);
        }
        logger.info("claims.getId()=" + claims.getId());
        //前端调用findByToken接口检查过了,所以这里不再对会员是否存在和状态进行判断

        Member memberInDb = memberService.findById(claims.getId());
        String realName = map.get("real_name");
        if ("".equals(realName) || null == realName) {
            return new Result(StatusCode.ERROR_REAL_NAME_REQUIRED);
        }
        String idCard = map.get("id_card");
        if ("".equals(idCard) || null == idCard) {
            return new Result(StatusCode.ERROR_ID_CARD_REQUIRED);
        }
        //通过token获取用户
        memberInDb.setRealName(realName);
        memberInDb.setIdCard(idCard);

        return new Result(StatusCode.FAIL_VERIFY);
    }


    /**
     * 查询全部数据
     *
     * @return
     */
    @RequestMapping(method = RequestMethod.GET)
    public Result findAll() {
        return new Result(StatusCode.SUCCESS_QUERY, memberService.findAll());
    }

    /**
     * 分页+多条件查询
     *
     * @param searchMap 查询条件封装
     * @param page      页码
     * @param size      页大小
     * @return 分页结果
     */
    @RequestMapping(value = "/search/{page}/{size}", method = RequestMethod.POST)
    public Result findSearch(@RequestBody Map searchMap, @PathVariable int page, @PathVariable int size) {
        Page<Member> pageList = memberService.findSearch(searchMap, page, size);
        logger.info(pageList.toString());
        return new Result(StatusCode.SUCCESS_QUERY, new PageResult<>(pageList.getTotalElements(), pageList.getContent()));
    }

    /**
     * 根据条件查询
     *
     * @param searchMap
     * @return
     */
    @RequestMapping(value = "/search", method = RequestMethod.POST)
    public Result findSearch(@RequestBody Map searchMap) {
        return new Result(StatusCode.SUCCESS_QUERY, memberService.findSearch(searchMap));
    }

    /**
     * 发送订阅消息
     *
     * @param phone
     * @return
     */
    @RequestMapping(value = "/send/{phone}", method = RequestMethod.POST)
    public Result send(@PathVariable String phone) {
        memberService.sendOrderMassage(phone);
        return new Result(StatusCode.SUCCESS, "订购成功");
    }

    /**
     * 暂时不传递参数以后再考虑传参数
     * @return
     */
    @RequestMapping(value = "/share/poster",method = RequestMethod.GET)
    public Result getPoster(){
         Claims claims=(Claims)request.getAttribute("robot_member");
         if(claims==null){
             return new Result(StatusCode.ERROR_TOKEN_EXPIRED);
         }
        logger.info("claims.getId()=" + claims.getId());
        Member member = memberService.findById(claims.getId());

        PosterUtil posterUtil=new PosterUtil();
        String backgroundImage="https://mashangjie-prod.oss-cn-qingdao.aliyuncs.com/posterbg.jpg";
        //构建昵称对象
        String nickname=member.getNickname();
        NickName nickName=new NickName(nickname,45,88,5);

        //构建头像对象
        String headImageUrl=member.getAvatar();
        HeadImage headImage=new HeadImage(headImageUrl,18,18,18,83);

        //构建二维码对象
        String qrText="http://member.mashangjie.shop/#/pages/wechatlogin/wechatlogin?recommendId="+member.getId();
        QrCode qrCode=new QrCode(qrText,50,50,25,50);

        HashMap<String,String> result=new HashMap<>();
        result.put("base64",posterUtil.posterCreate(backgroundImage,nickName,headImage,qrCode));
        return new Result(StatusCode.SUCCESS,result);
    }
}